package org.zhangkun.jmsg.ui.swing.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTree;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;
import javax.swing.event.TreeModelListener;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import org.zhangkun.jmsg.bean.User;
import org.zhangkun.jmsg.core.UserManager;
import org.zhangkun.jmsg.core.listener.UserListener;
import org.zhangkun.jmsg.ui.swing.MainWindow;
import org.zhangkun.jmsg.ui.swing.SendFileDialog;
import org.zhangkun.jmsg.util.Res;

public class UserTreePanel extends JPanel implements UserListener {

    private static final Border DEFAULT_NO_FOCUS_BORDER = new EmptyBorder(1, 1,
            1, 1);
    protected static Border noFocusBorder = DEFAULT_NO_FOCUS_BORDER;

    private class GroupStrLabel extends JPanel {
        /**
         *
         */
        private static final long serialVersionUID = -1938296975288057802L;
        private boolean open;
        private String str;

        public GroupStrLabel() {
            setOpaque(true);
            setBackground(Color.getColor("#00000000"));
        }

        @Override
        protected void paintComponent(Graphics g) {
            // TODO Auto-generated method stub
            super.paintComponent(g);

            // Graphics2D g2d = (Graphics2D) g;
            // g2d.setColor(getBackground());
            // g2d.fillRoundRect(1, 1, getWidth() - 2, getHeight() - 2, 10, 15);
            // g.setColor(getForeground());
            g.translate(5, 5);
            if (open)
                g.drawImage(Res.GROUP_OPEN, 2, 4, this);
            else
                g.drawImage(Res.GROUP_CLOSE, 3, 2, this);
            g.drawString(str + "  [" + UserManager.instance.getUser(str).length
                    + "]", 15, g.getFontMetrics().getAscent());
        }

        public void setText(String str) {
            // TODO Auto-generated method stub
            this.str = str;
            // setPreferredSize(new Dimension(tree.getPreferredSize().width -
            // 10,
            // (getFontMetrics(getFont()).getHeight() + 10)));
            int w = getFontMetrics(getFont()).stringWidth(
                    str + "  [" + UserManager.instance.getUser(str).length
                            + "]") + 40;
            setPreferredSize(new Dimension(w, (getFontMetrics(getFont())
                    .getHeight() + 10)));
        }
    }

    class MyTreeUI extends BasicTreeUI {

        @Override
        protected void paintHorizontalLine(Graphics g, JComponent c, int y,
                                           int left, int right) {
        }

        // 实现去除JTree的垂直线和水平线
        @Override
        protected void paintVerticalLine(Graphics g, JComponent c, int x,
                                         int top, int bottom) {
        }

        // 实现父节点与子节点对齐
        @Override
        public void setLeftChildIndent(int newAmount) {
        }

        @Override
        public void setRightChildIndent(int newAmount) {

        }
    }

    private class UserListModel extends DefaultTreeModel {

        /**
         *
         */
        private static final long serialVersionUID = -8439704743327079751L;

        private final Integer ROOT = new Integer(1);

        public UserListModel(TreeNode arg0) {
            super(arg0);
            // TODO Auto-generated constructor stub
        }

        @Override
        public void addTreeModelListener(TreeModelListener l) {
            // TODO Auto-generated method stub

        }

        @Override
        public Object getChild(Object parent, int index) {
            // TODO Auto-generated method stub
            // System.out.println("getChild " + parent + " index " + index);
            if (parent instanceof Integer) {
                String[] groups = UserManager.instance.getGroups();
                if (index >= 0 && index < groups.length)
                    return groups[index];
                return null;
            } else {
                User[] users = UserManager.instance.getUser(parent.toString());
                if (index >= 0 && index < users.length)
                    return users[index];
                return null;
            }
        }

        @Override
        public int getChildCount(Object parent) {
            // TODO Auto-generated method stub
            // System.out.println("getChildCount " + parent);
            if (parent instanceof Integer) {
                // System.out.println(UserManager.instance.getGroups().length);
                return UserManager.instance.getGroups().length;
            } else {
                // System.out.println(UserManager.instance.getUser(parent
                // .equals(NOGROUPSTR) ? "" : parent.toString()).length);
                return UserManager.instance.getUser(parent.toString()).length;
            }
        }

        @Override
        public int getIndexOfChild(Object parent, Object child) {
            // TODO Auto-generated method stub
            // System.out.println("getIndexOfChild " + parent + " child " +
            // child);
            if (parent instanceof Integer) {
                String[] groups = UserManager.instance.getGroups();
                for (int i = 0; i < groups.length; i++)
                    if (groups[i].equals(child))
                        return i;
                return -1;
            } else {
                User[] groups = UserManager.instance.getUser(child.toString());
                for (int i = 0; i < groups.length; i++)
                    if (groups[i].equals(child))
                        return i;
                return -1;
            }
        }

        @Override
        public Object getRoot() {
            // TODO Auto-generated method stub
            return ROOT;
        }

        @Override
        public boolean isLeaf(Object node) {
            // TODO Auto-generated method stub
            if (node instanceof User)
                return true;
            return false;
        }

        @Override
        public void removeTreeModelListener(TreeModelListener l) {
            // TODO Auto-generated method stub

        }

        @Override
        public void valueForPathChanged(TreePath path, Object newValue) {
            // TODO Auto-generated method stub

        }
    }

    private class UserTreeCellRenderer extends DefaultTreeCellRenderer {

        /**
         *
         */
        private static final long serialVersionUID = -9133754713921625724L;
        private JCheckBox cb = new JCheckBox();
        private GroupStrLabel lab = new GroupStrLabel();
        private JPanel panel = new JPanel();
        private Color systemListBackground;

        private Color systemListForeground;

        private UserItemLab userLab = new UserItemLab();

        public UserTreeCellRenderer() {
            panel.setBackground(Color.getColor("#00000000"));
            panel.setLayout(new BorderLayout());
            if (showMode == SHOW_MODEL_SELECTION)
                panel.add(cb, BorderLayout.WEST);
            panel.add(userLab, BorderLayout.CENTER);
            initColor();
        }

        @Override
        public Component getTreeCellRendererComponent(JTree tree, Object value,
                                                      boolean isSelected, boolean expanded, boolean leaf, int row,
                                                      boolean hasFocus) {
            // TODO Auto-generated method stub
            Color background;
            Color foreground;
            if (isSelected) {
                background = systemListBackground;
                // background = getSelectionBackground();
                foreground = systemListForeground;
                // foreground = getSelectionForeground();
                // unselected, and not the DnD drop location
            } else {
                // background = UIManager.getLookAndFeel().getDefaults()
                // .getColor("List.background");
                // foreground = UIManager.getLookAndFeel().getDefaults()
                // .getColor("List.foreground");
                background = getBackground();
                foreground = getForeground();
            }
            int width = UserTreePanel.this.getSize().width
                    - (showMode == SHOW_MODEL_SELECTION ? 15 : 5);
            // System.out.println("width " + width);

            if (value instanceof User) {
                User u = (User) value;
                userLab.setUser(u);
                panel.setBackground(background);
                panel.setForeground(foreground);
                userLab.setBackground(background);
                userLab.setForeground(foreground);
                if (selUser.contains(value))
                    cb.setSelected(true);
                else
                    cb.setSelected(false);
                panel.doLayout();
                int pw = 0;
                int ph = 0;
                if (width > 0
                        && userLab.getPreferredSize().width
                        + (showMode == SHOW_MODEL_SELECTION ? 40 : 0) < width) {
                    pw = width;
                    ph = (userLab.getFontMetrics(userLab.getFont()).getHeight() + 3) * 2;
                } else {
                    pw = userLab.getPreferredSize().width + (showMode == SHOW_MODEL_SELECTION ? 40 : 0);
                    ph = (userLab.getFontMetrics(userLab.getFont()).getHeight() + 3) * 2;
                }
                panel.setPreferredSize(new Dimension(pw, ph));
                return panel;
            } else {
                lab.setText(value.toString());
                lab.setBackground(background);
                lab.setForeground(foreground);
                lab.open = expanded;
                if (width > 0 && lab.getPreferredSize().width < width)
                    lab.setPreferredSize(new Dimension(width, (lab
                            .getFontMetrics(lab.getFont()).getHeight() + 10)));
                return lab;
            }
        }

        @Override
        public boolean isOpaque() {
            Color back = getBackground();
            Component p = getParent();
            if (p != null) {
                p = p.getParent();
            }
            // p should now be the JList.
            boolean colorMatch = (back != null) && (p != null)
                    && back.equals(p.getBackground()) && p.isOpaque();
            return !colorMatch && super.isOpaque();
        }

        public void initColor() {
            systemListBackground = UIManager.getLookAndFeel().getDefaults()
                    .getColor("List.selectionBackground");
            systemListForeground = UIManager.getLookAndFeel().getDefaults()
                    .getColor("List.selectionForeground");
        }
    }

    /**
     *
     */
    private static final long serialVersionUID = 1939401203443349481L;

    public final static int SHOW_MODEL_LIST = 2;

    public final static int SHOW_MODEL_SELECTION = 1;
    private UserListModel model = new UserListModel(null);
    private ArrayList<User> selUser = new ArrayList<User>();
    private int showMode;

    private JTree tree;

    private MyTreeUI treeUI = new MyTreeUI();

    // private int width;

    public UserTreePanel(String title, int showMode) {
        this.showMode = showMode;
        setLayout(new BorderLayout());
        tree = new JTree();
        tree.setModel(model);
        tree.setCellRenderer(new UserTreeCellRenderer());
        UserManager.addUserListener(this);
        tree.setRootVisible(false);
        tree.putClientProperty("JTree.lineStyle", "None");
        tree.setUI(treeUI);
        tree.setScrollsOnExpand(true);
        tree.getSelectionModel().setSelectionMode(
                TreeSelectionModel.SINGLE_TREE_SELECTION);
        tree.setToggleClickCount(0);
        tree.setEditable(false);
        tree.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                // TODO Auto-generated method stub
                if (e.getClickCount() > 1) {
                    TreePath path = tree.getPathForLocation(e.getX(), e.getY());
                    if (path != null) {
                        Object value = path.getLastPathComponent();
                        if (value instanceof User)
                            MainWindow.instance.openSendDialog((User) value);
                        else {
                            MainWindow.instance.openGroupMsg();
                            MainWindow.instance.getGroupMsg()
                                    .getUserTreePanel().clearSel();
                            MainWindow.instance.getGroupMsg()
                                    .getUserTreePanel()
                                    .selGroup((String) value);
                        }
                    }
                }
            }

            @Override
            public void mousePressed(MouseEvent e) {
                // TODO Auto-generated method stub
                TreePath path = tree.getPathForLocation(e.getX(), e.getY());
                if (e.getClickCount() == 1
                        && e.getButton() == MouseEvent.BUTTON1) {
                    if (path == null) {
                        tree.setSelectionPath(null);
                        return;
                    }
                    if (path.getLastPathComponent() instanceof User) {
                        if (path.equals(tree.getSelectionPath())) {
                            if (UserTreePanel.this.showMode == SHOW_MODEL_SELECTION) {
                                User user = (User) path.getLastPathComponent();
                                if (!selUser.contains(user))
                                    selUser.add(user);
                                else
                                    selUser.remove(user);
                                updateTree();
                            }
                        }
                    } else {
                        if (tree.isExpanded(path))
                            tree.collapsePath(path);
                        else
                            tree.expandPath(path);
                    }
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                // TODO Auto-generated method stub
                if (e.getButton() == MouseEvent.BUTTON3) {
                    createPopupMenu(e.getX(), e.getY());
                }

            }

        });

        if (showMode == SHOW_MODEL_SELECTION)
            tree.setBorder(new TitledBorder(null, title, TitledBorder.LEADING,
                    TitledBorder.TOP, null, null));
        else
            setBorder(new EmptyBorder(5, 3, 5, 0));

        final JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewportBorder(BorderFactory.createEmptyBorder());
        scrollPane.setViewportView(tree);
        add(scrollPane, BorderLayout.CENTER);

        if (showMode == SHOW_MODEL_SELECTION) {
            final JButton button = new JButton("");
            button.setPreferredSize(new Dimension(5, 0));
            button.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    // if (scrollPane.isVisible())
                    // setPreferredSize(button.getPreferredSize());
                    scrollPane.setVisible(!scrollPane.isVisible());
                    revalidate();
                    getRootPane().revalidate();
                }
            });
            add(button, BorderLayout.WEST);
        }

        if (showMode == SHOW_MODEL_SELECTION)
            tree.addFocusListener(new FocusListener() {

                @Override
                public void focusLost(FocusEvent arg0) {
                    // TODO Auto-generated method stub
                    tree.setSelectionPath(null);
                }

                @Override
                public void focusGained(FocusEvent arg0) {
                    // TODO Auto-generated method stub

                }
            });

        expandAll(true);
    }

    @Override
    public void addUser(User u) {
        // TODO Auto-generated method stub
        updateTree();
    }

    @Override
    public void delAllUser() {
        // TODO Auto-generated method stub
        updateTree();
    }

    public void expandAll(boolean expand) {
        TreePath rootPath = new TreePath(model.getRoot());
        for (int i = 0; i < model.getChildCount(model.getRoot()); i++) {
            String groupStr = (String) model.getChild(model.getRoot(), i);
            TreePath group = rootPath.pathByAddingChild(groupStr);
            if (expand)
                tree.expandPath(group);
            else
                tree.collapsePath(group);
        }
    }

    public void expandGroup(String groupStr, boolean expand) {
        TreePath rootPath = new TreePath(model.getRoot());
        TreePath group = rootPath.pathByAddingChild(groupStr);
        if (expand)
            tree.expandPath(group);
        else
            tree.collapsePath(group);
    }

    public int findUserIndex(User u) {
        ArrayList<User> allUser = UserManager.instance.getAllUser();
        for (int i = 0; i < allUser.size(); i++)
            if (allUser.get(i).equals(u))
                return i;
        return -1;
    }

    public UserListModel getModel() {
        return model;
    }

    public Object getSelect() {
        TreePath path = tree.getSelectionPath();
        if (path != null)
            return path.getLastPathComponent();
        return null;
    }

    public ArrayList<User> getSelUser() {
        for (int i = selUser.size() - 1; i >= 0; i--) {
            User user = selUser.get(i);
            if (!UserManager.instance.getAllUser().contains(user))
                selUser.remove(user);
        }
        return selUser;
    }

    public int getShowMode() {
        return showMode;
    }

    public JTree getTree() {
        return tree;
    }

    public MyTreeUI getTreeUI() {
        return treeUI;
    }

    @Override
    public void modifyUser(User u) {
        // TODO Auto-generated method stub
        updateTree();
    }

    @Override
    public void removeUser(User u) {
        // TODO Auto-generated method stub
        updateTree();
    }

    public void scrollTo(User user) {
        TreePath root = new TreePath(1);
        TreePath group = root.pathByAddingChild(user.getGroup());
        TreePath path = group.pathByAddingChild(user);
        // tree.scrollPathToVisible(path);
        tree.setSelectionPath(path);
    }

    public void selUser(User user) {
        // TODO Auto-generated method stub
        if (!selUser.contains(user))
            selUser.add(user);
        scrollTo(user);
    }

    public void selAll() {
        ArrayList<User> user = UserManager.instance.getAllUser();
        for (int i = 0; i < user.size(); i++)
            if (!selUser.contains(user.get(i)))
                selUser.add(user.get(i));
        expandAll(true);
        updateTree();
    }

    public void selGroup(String group) {
        User[] user = UserManager.instance.getUser(group);
        for (int i = 0; i < user.length; i++)
            if (!selUser.contains(user[i]))
                selUser.add(user[i]);
        expandGroup(group, true);
    }

    public void setModel(UserListModel model) {
        this.model = model;
    }

    public void setSelUser(ArrayList<User> selUser) {
        this.selUser = selUser;
    }

    public void setShowMode(int showMode) {
        this.showMode = showMode;
    }

    public void setTree(JTree tree) {
        this.tree = tree;
    }

    public void setTreeUI(MyTreeUI treeUI) {
        this.treeUI = treeUI;
    }

    public void updateTree() {
        if (tree != null) {
            model.reload();
            tree.updateUI();
            tree.setUI(treeUI);
            tree.setBackground(Color.getColor("#00000000"));
            ((UserTreeCellRenderer) tree.getCellRenderer()).initColor();
        }
    }

    public void createPopupMenu(int x, int y) {
        JPopupMenu menu = new JPopupMenu();

        JSeparator separator;

        TreePath path = tree.getPathForLocation(x, y);

        if (path != null) {
            separator = new JSeparator();
            menu.add(separator);
            JMenuItem menuItem = new JMenuItem("发送消息");
            menuItem.setIcon(new ImageIcon(MainWindow.class
                    .getResource("/res/mail-message-new.png")));
            menuItem.addActionListener(new ActionListener() {
                private Object value;

                public void actionPerformed(ActionEvent e) {
                    if (value instanceof User)
                        MainWindow.instance.openSendDialog((User) value);
                    else {
                        MainWindow.instance.openGroupMsg();
                        MainWindow.instance.getGroupMsg().getUserTreePanel()
                                .clearSel();
                        MainWindow.instance.getGroupMsg().getUserTreePanel()
                                .selGroup((String) value);
                    }
                }

                public ActionListener setValue(Object value) {
                    this.value = value;
                    return this;
                }
            }.setValue(path.getLastPathComponent()));
            menu.add(menuItem);
            menuItem = new JMenuItem("发送文件");
            menuItem.setIcon(new ImageIcon(MainWindow.class
                    .getResource("/res/document-new.png")));
            menuItem.addActionListener(new ActionListener() {
                private Object value;

                public void actionPerformed(ActionEvent e) {
                    if (value instanceof User)
                        new SendFileDialog((User) value);
                    else {
                        SendFileDialog sfd = new SendFileDialog();
                        sfd.getUserTreePanel().clearSel();
                        sfd.getUserTreePanel().selGroup((String) value);
                    }
                }

                public ActionListener setValue(Object value) {
                    this.value = value;
                    return this;
                }
            }.setValue(path.getLastPathComponent()));
            menu.add(menuItem);
            separator = new JSeparator();
            menu.add(separator);
        }

        JMenuItem refreshMenuItem = menu.add("刷新好友");
        refreshMenuItem.setIcon(new ImageIcon(MainWindow.class
                .getResource("/res/view-refresh.png")));
        refreshMenuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                MainWindow.instance.refresh();
            }
        });

        if (showMode == SHOW_MODEL_SELECTION) {
            JMenuItem selAllMenuItem = menu.add("全部选择");
            selAllMenuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    selAll();
                }
            });
            JMenuItem selReverseMenuItem = menu.add("反向选择");
            selReverseMenuItem.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent arg0) {
                    // TODO Auto-generated method stub
                    selReverse();
                }
            });
        }
        JMenuItem expandAllMenuItem = menu.add("全部展开");
        expandAllMenuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                expandAll(true);
            }
        });
        JMenuItem closeAllMenuItem = menu.add("全部收起");
        closeAllMenuItem.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                expandAll(false);
            }
        });

        separator = new JSeparator();
        menu.add(separator);
        JMenuItem pocketTransmissionItem = menu.add("群发消息");
        pocketTransmissionItem.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                MainWindow.instance.openGroupMsg();
                MainWindow.instance.getGroupMsg().getUserTreePanel().selAll();
            }
        });
        pocketTransmissionItem.setIcon(new ImageIcon(MainWindow.class
                .getResource("/res/im-message-new.png")));
        menu.add(pocketTransmissionItem);

        separator = new JSeparator();
        menu.add(separator);

        JMenuItem about = menu.add("关于");
        about.setIcon(new ImageIcon(MainWindow.class
                .getResource("/res/help-about.png")));
        about.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                // TODO Auto-generated method stub
                MainWindow.instance.about();
            }
        });
        menu.show(tree, x, y);
    }

    private void selReverse() {
        // TODO Auto-generated method stub
        ArrayList<User> allUser = UserManager.instance.getAllUser();
        for (int i = 0; i < allUser.size(); i++) {
            if (selUser.contains(allUser.get(i)))
                selUser.remove(allUser.get(i));
            else
                selUser.add(allUser.get(i));
        }
        updateTree();
    }

    public void clearSel() {
        selUser.clear();
        updateTree();
    }

}
